import { CommonModule } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  inject,
  OnInit,
  signal,
} from '@angular/core';
import { NzButtonModule } from 'ng-zorro-antd/button';
import { HttpService } from './service/http.service';
import {
  debounceTime,
  finalize,
  forkJoin,
  Observable,
  of,
  Subject,
  switchMap,
  takeUntil,
  tap,
  timer,
} from 'rxjs';
import { NzMessageService } from 'ng-zorro-antd/message';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NzInputModule } from 'ng-zorro-antd/input';
import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'login',
  imports: [
    NzButtonModule,
    CommonModule,
    NzInputModule,
    NzAutocompleteModule,
    FormsModule,
  ],
  template: `
    <button
      nz-button
      nzType="primary"
      (click)="getHello(true)"
      [nzLoading]="loading()"
    >
      render text
    </button>
    <button
      nz-button
      nzType="primary"
      (click)="addList()"
      [nzLoading]="loading()"
    >
      add list
    </button>
    <button nz-button nzDanger (click)="getHello()" [nzLoading]="loading()">
      失败打印
    </button>
    <br />
    text:
    <p>{{ text() }}</p>

    list: @for (item of list(); track $index; let idx = $index) {
    <div>{{ idx + 1 }}-{{ item }}</div>
    }
    <br />
    angular常见的http处理
    <button nz-button (click)="catchData()" [nzLoading]="loading()">
      获取缓存数据
    </button>

    <button nz-button (click)="httpMerge()" [nzLoading]="loading()">
      并发请求http
    </button>

    <button nz-button (click)="mergeOnce()">相同请求合并</button>
    <button nz-button (click)="cancelPre()">取消上一次http请求</button>

    <br />
    input实践
    <input
      placeholder="input here"
      nz-input
      [(ngModel)]="inputVal"
      (input)="onInput($event)"
      [nzAutocomplete]="auto"
    />
    <nz-autocomplete
      [nzDataSource]="options()"
      nzBackfill
      #auto
    ></nz-autocomplete>
  `,
  styleUrl: './login.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginComponent implements OnInit {
  ngOnInit(): void {
    this.initSearch();
  }
  private httpService = inject(HttpService);
  private messageService = inject(NzMessageService);
  private destroyRef = inject(DestroyRef);
  $searchVal = new Subject<string>();
  loading = signal(false);
  text = signal('');
  list = signal<string[]>([]);

  getHello(flag = false) {
    this.loading.set(true);
    this.httpService
      .getHello(flag)
      .pipe(
        takeUntilDestroyed(this.destroyRef),
        finalize(() => {
          this.loading.set(false);
        })
      )
      .subscribe({
        next: (res) => {
          this.text.set(res);
        },
        error: (err) => {
          this.messageService.error(JSON.stringify(err));
        },
      });
  }
  addList() {
    this.loading.set(true);
    this.httpService
      .getHello(true)
      .pipe(
        takeUntilDestroyed(this.destroyRef),
        finalize(() => {
          this.loading.set(false);
        })
      )
      .subscribe({
        next: (res) => {
          this.list.set([...this.list(), res]);
          this.messageService.success('添加成功');
        },
        error: (err) => {
          this.messageService.error(JSON.stringify(err));
        },
      });
  }
  catchData() {
    this.loading.set(true);
    this.httpService
      .getCatchData()
      .pipe(
        finalize(() => {
          this.loading.set(false);
        })
      )
      .subscribe({
        next: (res) => {
          this.messageService.success('获取成功' + res);
        },
        error: (err) => {
          this.messageService.error(JSON.stringify(err));
        },
      });
  }
  httpMerge() {
    this.loading.set(true);
    forkJoin([
      this.httpService.getHello(true),
      this.httpService.getHello(true),
      this.httpService.getHello(true),
    ])
      .pipe(
        finalize(() => {
          this.loading.set(false);
        })
      )
      .subscribe({
        next: (res) => {
          this.messageService.success('获取成功' + JSON.stringify(res));
        },
        error: (err) => {
          this.messageService.error(JSON.stringify(err));
        },
      });
  }
  clickTime = 0;
  mergeOnce() {
    this.clickTime++;
    this.httpService.getOnceData().subscribe({
      next: (res) => {
        this.messageService.success(
          '获取成功' + '点击了' + this.clickTime + '次' + JSON.stringify(res)
        );
        timer(500).subscribe(() => {
          this.clickTime = 0;
        });
      },
      error: (err) => {
        this.messageService.error(JSON.stringify(err));
      },
    });
  }
  httpPre = new Observable<string>();
  httpDestroy = new Subject<void>();
  cancelHttp() {
    this.httpPre = this.httpService
      .getHello(true)
      .pipe(takeUntil(this.httpDestroy));
    return this.httpPre;
  }

  cancelPre() {
    if (this.httpPre) {
      this.httpDestroy.next();
      this.httpDestroy.complete();
      this.httpDestroy = new Subject<void>();
    }

    this.cancelHttp().subscribe({
      next: (res) => {
        this.messageService.success('获取成功' + res);
      },
      error: (err) => {
        this.messageService.error(JSON.stringify(err));
      },
      complete: () => {
        this.messageService.info('请求已取消或完成');
      },
    });
  }
  initSearch() {
    this.$searchVal
      .pipe(
        tap(() => {
          this.httpDestroy.next();
        }), // 清除上一次的请求
        debounceTime(500), // 防抖处理
        switchMap((val) => {
          if (!val) {
            return of([]);
          }
          return this.httpService
            .getList(val)
            .pipe(
              takeUntil(this.httpDestroy),
              takeUntilDestroyed(this.destroyRef)
            );
        }),
        takeUntilDestroyed(this.destroyRef) // 销毁时取消订阅
      )
      .subscribe({
        next: (res) => {
          this.options.set(res);
        },
        error: (err) => {
          this.messageService.error(JSON.stringify(err));
        },
      });
  }
  inputVal = signal('');
  options = signal<string[]>([]);
  onInput(e: Event) {
    const target = e.target as HTMLInputElement | null;
    if (target) {
      this.$searchVal.next(this.inputVal());
    } else {
      this.$searchVal.next('');
    }
  }
}
